//

//  main.m

//  ProcessTreeTest

//

//  Created by suixinyuan on 2017/8/9.

//  Copyright © 2017年 NetEaseExam. All rights reserved.

//



#import <Foundation/Foundation.h>



@interface NSString (Process)



- (NSString *)getProcessName;



+ (NSString *)dividerByDepthArray:(NSMutableArray<NSNumber *> *)arr;



@end



@implementation NSString (Process)



- (NSString *)getProcessName{
    
    
    
    NSArray *splitArr = [self componentsSeparatedByString:@"\n"];
    
    NSString *name = [NSString string];
    
    name = splitArr[0];
    
    return name;
    
}



+ (NSString *)dividerByDepthArray:(NSMutableArray<NSNumber *> *)subdepthArr{
    
    
    
    NSMutableString *baseDivider = [NSMutableString string];
    
    [baseDivider appendString:@"\n"];
    
    
    
    if (subdepthArr!=nil && subdepthArr.count>0) {
        
        for (int i = 0; i<subdepthArr.count-1; i++) {
            
            if ([subdepthArr[i] boolValue]==YES) {
                
                [baseDivider appendString:@"  "];
                
            }else{
                
                [baseDivider appendString:@"│ "];
                
            }
            
        }
        
        if ([subdepthArr[subdepthArr.count-1] boolValue]==YES) {
            
            [baseDivider appendString:@"└─"];
            
        }else{
            
            [baseDivider appendString:@"├─"];
            
        }
        
    }
    
    
    
    NSString *result = [baseDivider copy];
    
    
    
    return result;
    
}



@end



@interface Process : NSObject



@property (nonatomic) NSString *name;   // 进程名

@property (nonatomic) NSArray<Process *> *children; // 子进程



- (instancetype)initWithName:(NSString*)name children:(NSArray<Process *> *)children;

- (instancetype)initFromDumpString:(NSString*)dump;

- (NSString*)dump;



@end



@implementation Process



- (instancetype)initWithName:(NSString*)name children:(NSArray<Process *> *)children {
    
    if (self = [super init]) {
        
        _name = name;
        
        _children = children;
        
    }
    
    return self;
    
}



//1.字符串转进程树

- (instancetype)initFromDumpString:(NSString*)dump{
    
    
    
    NSMutableArray *depthArr = [NSMutableArray array];
    
    
    
    Process* node0 = [[Process alloc] init];
    
    
    
    //去掉首个换行符 转换为可以进行递归操作的字符串
    
    NSArray *arr0 = [dump componentsSeparatedByString:@"\n"];
    
    NSMutableArray *arr01 = [arr0 mutableCopy];
    
    [arr01 removeObjectAtIndex:0];
    
    NSString *logger0 = [arr01 componentsJoinedByString:@"\n"];
    
    NSMutableString *logger = [logger0 mutableCopy];
    
    
    
    [Process stringToNode:node0 string:logger depthArray:depthArr];
    
    
    
    return node0;
    
    
    
}



/* *
 
 * 固定格式字符串（以节点名称开头）转化为节点
 
 * logger:初始化字符串
 
 * node:传入节点
 
 * depthArr:传入节点深度序列 depthArr.count为节点深度 1 表示是最后一个元素 0表示是中间元素
 
 */

- (void)stringToNode:(Process *)node string:(NSMutableString *)logger depthArray:(NSMutableArray *)depthArr{
    
    //初始化此节点的子节点
    
    NSMutableArray *nodeChilds = [NSMutableArray array];
    
    
    
    node.name = [logger getProcessName];
    
    //*********开始计算尾部子节点*********
    
    //计算此节点最后一个子节点的深度序列
    
    NSMutableArray *subdepthArr = [depthArr mutableCopy];
    
    [subdepthArr addObject:@1];
    
    //计算最后一个子节点的分隔符
    
    NSString *lastDivider = [NSString dividerByDepthArray:subdepthArr];
    
    
    
    //将这个分为两个字符串 根节点与中间节点+最后一个子节点
    
    NSArray *middlesAndLastArr = [logger componentsSeparatedByString:lastDivider];
    
    
    
    if (middlesAndLastArr.count == 2) {//分割成功 表示有子node
        
        Process *subNodeLast = [[Process alloc] init];
        
        subNodeLast.name = [middlesAndLastArr[1] getProcessName];
        
        //        NSLog(@"last--%@", subNodeLast.name);
        
        
        
        [nodeChilds addObject:subNodeLast];
        
        node.children = nodeChilds;
        
        
        
        //递归生成子节点
        
        [self stringToNode:subNodeLast string:middlesAndLastArr[1] depthArray:subdepthArr];
        
        
        
        //*********开始计算中间子节点*********
        
        //计算此节点中间子节点的深度序列
        
        NSMutableArray *subdepthArr = [depthArr mutableCopy];
        
        [subdepthArr addObject:@0];
        
        //计算中间子节点的分隔符
        
        NSString *middleDivider = [NSString dividerByDepthArray:subdepthArr];
        
        //将这个分为1+n个字符串 1为根节点 n为中间子节点
        
        NSArray *middlesArr = [middlesAndLastArr[0] componentsSeparatedByString:middleDivider];
        
        if (middlesArr.count>=2) {//如果分割成功，表示有中间元素
            
            
            
            for (int i=1; i<middlesArr.count; i++) {
                
                Process *subNode = [[Process alloc] init];
                
                subNode.name = [middlesArr[i] getProcessName];
                
                
                
                //                NSLog(@"middle--%@", subNode.name);
                
                
                
                [nodeChilds addObject:subNode];
                
                node.children = nodeChilds;
                
                
                
                //递归生成子节点
                
                [self stringToNode:subNode string:middlesArr[i] depthArray:subdepthArr];
                
            }
            
            
            
        }
        
    }
    
}





/* *
 
 * 固定格式字符串（以节点名称开头）转化为节点
 
 * logger:初始化字符串
 
 * node:传入节点
 
 * depthArr:传入节点深度序列 depthArr.count为节点深度 1 表示是最后一个元素 0表示是中间元素
 
 */

+ (void)stringToNode:(Process *)node string:(NSMutableString *)logger depthArray:(NSMutableArray *)depthArr{
    
    //初始化此节点的子节点
    
    NSMutableArray *nodeChilds = [NSMutableArray array];
    
    node.name = [logger getProcessName];
    
    //*********开始计算尾部子节点*********
    
    //计算此节点最后一个子节点的深度序列
    
    NSMutableArray *subdepthArr = [depthArr mutableCopy];
    
    [subdepthArr addObject:@1];
    
    //计算最后一个子节点的分隔符
    
    NSString *lastDivider = [NSString dividerByDepthArray:subdepthArr];
    
    
    
    //将这个分为两个字符串 根节点与中间节点+最后一个子节点
    
    NSArray *middlesAndLastArr = [logger componentsSeparatedByString:lastDivider];
    
    
    
    if (middlesAndLastArr.count == 2) {//分割成功 表示有子node
        
        Process *subNodeLast = [[Process alloc] init];
        
        subNodeLast.name = [middlesAndLastArr[1] getProcessName];
        
        //        NSLog(@"last--%@", subNodeLast.name);
        
        
        
        [nodeChilds addObject:subNodeLast];
        
        node.children = nodeChilds;
        
        
        
        //递归生成子节点
        
        [Process stringToNode:subNodeLast string:middlesAndLastArr[1] depthArray:subdepthArr];
        
        
        
        //*********开始计算中间子节点*********
        
        //计算此节点中间子节点的深度序列
        
        NSMutableArray *subdepthArr = [depthArr mutableCopy];
        
        [subdepthArr addObject:@0];
        
        //计算中间子节点的分隔符
        
        NSString *middleDivider = [NSString dividerByDepthArray:subdepthArr];
        
        //将这个分为1+n个字符串 1为根节点 n为中间子节点
        
        NSArray *middlesArr = [middlesAndLastArr[0] componentsSeparatedByString:middleDivider];
        
        if (middlesArr.count>=2) {//如果分割成功，表示有中间元素
            
            
            
            for (int i=1; i<middlesArr.count; i++) {
                
                Process *subNode = [[Process alloc] init];
                
                subNode.name = [middlesArr[i] getProcessName];
                
                
                
                //                NSLog(@"middle--%@", subNode.name);
                
                
                
                [nodeChilds addObject:subNode];
                
                node.children = nodeChilds;
                
                
                
                //递归生成子节点
                
                [Process stringToNode:subNode string:middlesArr[i] depthArray:subdepthArr];
                
            }
            
        }
        
    }
    
}







//2.进程树转字符串

- (NSString*)dump {
    
    NSMutableString *logger = [NSMutableString string];
    
    NSMutableArray *depthArr = [NSMutableArray array];
    
    Process *node0 = self;
    
    [Process nodeToString:logger node:node0 depthArray:depthArr];
    
    return logger;
    
}



/* *
 
 * 节点转固定格式字符串
 
 * logger:初始化字符串
 
 * node:传入节点
 
 * depthArr:传入节点深度序列 depthArr.count为节点深度 1 表示是最后一个元素 0表示是中间元素
 
 */

- (void)nodeToString:(NSMutableString *)logger node:(Process *)node depthArray:(NSMutableArray *)depthArr{
    
    [logger appendString:@"\n"];
    
    if (depthArr!=nil && depthArr.count>0) {
        
        for (int i = 0; i<depthArr.count-1; i++) {
            
            if ([depthArr[i] boolValue]==YES) {
                
                [logger appendString:@"  "];
                
            }else{
                
                [logger appendString:@"│ "];
                
            }
            
        }
        
        if ([depthArr[depthArr.count-1] boolValue]==YES) {
            
            [logger appendString:@"└─"];
            
        }else{
            
            [logger appendString:@"├─"];
            
        }
        
    }
    
    [logger appendString:node.name];
    
    if (node.children!=nil && node.children.count>0) {
        
        for (int i=0; i<node.children.count-1; i++ ){
            
            NSMutableArray *subdepthArr = [depthArr mutableCopy];
            
            [subdepthArr addObject:@0];
            
            [self nodeToString:logger node:node.children[i] depthArray:subdepthArr];
            
        }
        
        Process *lastChidNode = node.children[node.children.count-1];
        
        NSMutableArray *subdepthArr = [depthArr mutableCopy];
        
        [subdepthArr addObject:@1];
        
        [self nodeToString:logger node:lastChidNode depthArray:subdepthArr];
        
    }
    
}





/* *
 
 * 节点转固定格式字符串
 
 * logger:初始化字符串
 
 * node:传入节点
 
 * depthArr:传入节点深度序列 depthArr.count为节点深度 1 表示是最后一个元素 0表示是中间元素
 
 */

+ (void)nodeToString:(NSMutableString *)logger node:(Process *)node depthArray:(NSMutableArray *)depthArr{
    
    [logger appendString:@"\n"];
    
    if (depthArr!=nil && depthArr.count>0) {
        
        for (int i = 0; i<depthArr.count-1; i++) {
            
            if ([depthArr[i] boolValue]==YES) {
                
                [logger appendString:@"  "];
                
            }else{
                
                [logger appendString:@"│ "];
                
            }
            
        }
        
        if ([depthArr[depthArr.count-1] boolValue]==YES) {
            
            [logger appendString:@"└─"];
            
        }else{
            
            [logger appendString:@"├─"];
            
        }
        
    }
    
    [logger appendString:node.name];
    
    if (node.children!=nil && node.children.count>0) {
        
        for (int i=0; i<node.children.count-1; i++ ){
            
            NSMutableArray *subdepthArr = [depthArr mutableCopy];
            
            [subdepthArr addObject:@0];
            
            [Process nodeToString:logger node:node.children[i] depthArray:subdepthArr];
            
        }
        
        Process *lastChidNode = node.children[node.children.count-1];
        
        NSMutableArray *subdepthArr = [depthArr mutableCopy];
        
        [subdepthArr addObject:@1];
        
        [Process nodeToString:logger node:lastChidNode depthArray:subdepthArr];
        
    }
    
}



@end



int main(int argc, const char * argv[]) {
    
    @autoreleasepool {
        
        // insert code here...
        
        NSString *zero = @"\nLauncher\n├─Xcode\n│ ├─Simulator\n│ └─Debugger\n├─Finder\n└─QQ";
        
        //字符串转进程
        
        Process *node0 = [[Process alloc] initFromDumpString:zero];
        
        //进程转字符串
        
        NSString *dump0 = [node0 dump];
        
        NSLog(@"字符串转进程树测试:%@", dump0);
        
        
        
        Process* xcode = [[Process alloc] initWithName:@"Xcode"
                          
                                              children:@[[[Process alloc] initWithName:@"Simulator" children:nil],
                                                         
                                                         [[Process alloc] initWithName:@"Debugger" children:nil]]];
        
        Process* finder = [[Process alloc] initWithName:@"Finder" children:nil];
        
        Process* qq = [[Process alloc] initWithName:@"QQ" children:nil];
        
        Process* launcher = [[Process alloc] initWithName:@"Launcher" children:@[xcode, finder, qq]];
        
        
        
        NSString *dumpStr0 = [launcher dump];
        
        
        
        NSLog(@"进程树转字符串测试:%@", dumpStr0);
        
        
        
        Process* aaa011 = [[Process alloc] initWithName:@"aaa011" children:nil];
        
        Process* aaa012 = [[Process alloc] initWithName:@"aaa012" children:nil];
        
        Process* aaa013 = [[Process alloc] initWithName:@"aaa013" children:nil];
        
        Process* aaa014 = [[Process alloc] initWithName:@"aaa014" children:nil];
        
        
        
        Process* aaa041 = [[Process alloc] initWithName:@"aaa041" children:nil];
        
        Process* aaa042 = [[Process alloc] initWithName:@"aaa042" children:nil];
        
        Process* aaa043 = [[Process alloc] initWithName:@"aaa043" children:nil];
        
        Process* aaa044 = [[Process alloc] initWithName:@"aaa044" children:nil];
        
        
        
        
        
        Process* aaa001 = [[Process alloc] initWithName:@"aaa001" children:@[aaa011,aaa012,aaa013,aaa014]];
        
        Process* aaa002 = [[Process alloc] initWithName:@"aaa002" children:nil];
        
        Process* aaa003 = [[Process alloc] initWithName:@"aaa003" children:nil];
        
        Process* aaa004 = [[Process alloc] initWithName:@"aaa004" children:@[aaa041,aaa042,aaa043,aaa044]];
        
        Process* aaa = [[Process alloc] initWithName:@"aaa" children:@[aaa001,aaa002,aaa003,aaa004]];
        
        
        
        Process* bbb = [[Process alloc] initWithName:@"bbb" children:@[aaa001,aaa004,aaa013,aaa004]];
        
        
        
        Process* ccc = [[Process alloc] initWithName:@"ccc" children:@[aaa001,aaa012,aaa004,aaa004]];
        
        
        
        Process* character = [[Process alloc] initWithName:@"Character" children:@[aaa,bbb,ccc]];
        
        
        
        //        Process* character = [[Process alloc] initWithName:@"Character" children:nil];
        
        //        launcher.children = @[aaa,bbb,ccc];
        
        
        
        NSLog(@"进程树转字符串测试2:%@", [character dump]);
        
    }
    
    return 0;
    
}


